﻿using FileImportSystem2.Services;
using SQLite;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using FileImportSystem2.Db.Entities;

namespace FileImportSystem2.Forms
{
    /// <summary>
    /// 文件导入系统主窗口
    /// 提供数据导入、匹配和导出功能的用户界面
    /// </summary>
    public partial class MainForm : Form
    {
        /// <summary>
        /// 记录用户选择的待导入文件列表
        /// </summary>
        private List<string> _selectedFiles = null!;

        /// <summary>
        /// 记录导入操作的开始时间，用于计算操作耗时
        /// </summary>
        private DateTime dt;
        #region 初始化窗体
        /// <summary>
        /// 初始化主窗口
        /// </summary>
        public MainForm()
        {
            InitializeComponent();
            // 获取并显示应用程序版本号
            var file = FileVersionInfo.GetVersionInfo(Application.ExecutablePath);
            this.Text = this.Text + " - " + file.FileVersion;
            // 设置窗体边框为固定对话框样式，禁止拖拽缩放
            this.FormBorderStyle = FormBorderStyle.FixedDialog;
            // 禁用最大化按钮
            this.MaximizeBox = false;
        }

        /// <summary>
        /// 窗口加载时执行的操作
        /// </summary>
        /// <param name="sender">事件发送者</param>
        /// <param name="e">事件参数</param>
        private void MainForm_Load(object sender, EventArgs e)
        {
            updateCmbMonth();
            LogMessage("系统已启动，准备就绪。");
        }

        /// <summary>
        /// 更新月份下拉框内容
        /// 从数据库目录读取已存在的月份数据文件，并更新下拉列表
        /// </summary>
        private void updateCmbMonth()
        {
            string _dbFd = AppConfig.dbMonFd;
            Directory.CreateDirectory(_dbFd);

            string[] files = Directory.GetFiles(_dbFd, "*.db");

            cmbMonth.Items.Clear();
            // 初始化月份下拉框,使用已有的月份文件
            foreach (var file in files)
            {
                string fileName = Path.GetFileNameWithoutExtension(file);
                cmbMonth.Items.Add(fileName);
            }
            // 默认选择当前月份
            if (cmbMonth.Items.Count > 0)
            {
                cmbMonth.SelectedIndex = cmbMonth.Items.Count - 1;
            }
            else
            {
                LogMessage("未找到任何月份数据库文件，请先导入数据。");
                btnExportData.Enabled = false;
                btnExportMissingInfo.Enabled = false;
            }
        }
        #endregion

        #region 日志记录
        /// <summary>
        /// 记录日志信息到界面文本框和本地日志文件
        /// </summary>
        /// <param name="message">日志消息内容</param>
        private void LogMessage(string message)
        {
            // 处理跨线程调用
            if (txtLog.InvokeRequired)
            {
                txtLog.Invoke(new Action<string>(LogMessage), message);
            }
            else
            {
                // 格式化日志条目，包含时间戳
                string logEntry = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}\n";
                txtLog.AppendText(logEntry);
                txtLog.ScrollToCaret();

                // 同时写入本地日志文件
                try
                {
                    string logDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs");
                    if (!Directory.Exists(logDirectory))
                    {
                        Directory.CreateDirectory(logDirectory);
                    }

                    string logFileName = $"{DateTime.Now:yyyyMMdd}.log";
                    string logFilePath = Path.Combine(logDirectory, logFileName);

                    using (StreamWriter writer = new StreamWriter(logFilePath, append: true))
                    {
                        writer.WriteLine(logEntry.TrimEnd('\n'));
                    }
                }
                catch (Exception ex)
                {
                    // 如果写入日志文件失败，记录在界面上但不抛出异常
                    string errorEntry = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 写入日志文件失败: {ex.Message}\n";
                    txtLog.AppendText(errorEntry);
                    txtLog.ScrollToCaret();
                }
            }
        }
        #endregion

        #region 导入数据库后台任务处理
        /// <summary>
        /// 后台工作线程执行的文件导入任务
        /// 支持单线程和多线程两种处理模式
        /// </summary>
        /// <param name="sender">事件发送者</param>
        /// <param name="e">事件参数，包含工作结果</param>
        private void backgroundWorker1_DoWorkAsync(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            int totalFiles = _selectedFiles.Count;
            int successCount = 0;
            int failCount = 0;

            int totalImported = 0;
            // 1: 单线程顺序处理, 2: 多线程并行处理
            int runType = 1;

            switch (runType)
            {
                case 1:
                    // 单线程顺序处理模式
                    for (int i = 0; i < _selectedFiles.Count; i++)
                    {
                        string file = _selectedFiles[i];
                        LogMessage($"开始处理文件[{i + 1}/{totalFiles}]: {file}");
                        // 创建文件导入服务实例
                        var importer = new Services.FileImporterService(file);
                        // 执行导入操作
                        (bool res, string mark, int ImpNum) = importer.Import();

                        if (res)
                        {
                            successCount++;
                            LogMessage($"文件处理成功[{i + 1}/{totalFiles}]: 记录数: {ImpNum}");
                            totalImported += ImpNum;
                        }
                        else
                        {
                            failCount++;
                            LogMessage($"文件处理失败[{i + 1}/{totalFiles}]: {mark}");
                        }
                        // 更新进度
                        int progressPercentage = (int)(((i + 1) / (float)_selectedFiles.Count) * 100);
                        backgroundWorker1.ReportProgress(progressPercentage);
                    }

                    e.Result = new
                    {
                        Success = failCount == 0,
                        Message = $"统计结果: (耗时 {(DateTime.Now - dt).ToString()}),成功 {successCount} 个，失败 {failCount} 个，总计导入 {totalImported} 条记录"
                    };
                    break;
                case 2:
                    // 多线程并行处理模式
                    // 按月份存储文件导入服务实例
                    Dictionary<string, Services.FileImporterService> dicDB = new Dictionary<string, Services.FileImporterService>();
                    // 使用线程安全的集合来收集每个任务的结果
                    System.Collections.Concurrent.ConcurrentBag<(bool res, string mark, int ImpNum)> resultsBag = new System.Collections.Concurrent.ConcurrentBag<(bool res, string mark, int ImpNum)>();
                    int processedCount = 0; // 已处理文件计数，用于进度报告
                    object lockObj = new object(); // 用于锁定计数操作

                    try
                    {
                        // 创建并行选项并设置最大并发数为 3
                        ParallelOptions options = new ParallelOptions
                        {
                            MaxDegreeOfParallelism = 5
                        };
                        // 使用 Parallel.ForEach 并行处理文件，但阻塞等待所有任务完成
                        Parallel.ForEach(_selectedFiles, options, (file) =>
                        {

                            LogMessage($"开始处理文件: {file}");

                            (string dateFull, string dateMonth) = FileNameServer.getDateFromFilePath(file);
                            Services.FileImporterService? importer;

                            // 注意：字典操作需要线程安全，这里使用锁来确保正确性
                            lock (dicDB)
                            {
                                if (!dicDB.TryGetValue(dateMonth, out importer))
                                {
                                    importer = new Services.FileImporterService(file);
                                    dicDB.Add(dateMonth, importer);
                                }
                            }

                            // 同步调用导入方法，并获取结果
                            var result = importer.Import(file); // 注意：这里应调用同步的 Import 方法
                            resultsBag.Add(result);


                            // 更新进度（需要线程安全操作）
                            int currentCount;
                            lock (lockObj)
                            {
                                processedCount++;
                                currentCount = processedCount;
                            }

                            if (!result.res)
                            {
                                // 如果 LogMessage 要更新UI，可能需要使用 Control.Invoke
                                LogMessage($"导入失败[{processedCount}/{totalFiles}]: {result.mark}:{file}");
                            }
                            else
                            {
                                LogMessage($"导入成功[{processedCount}/{totalFiles}]:处理数量: {result.ImpNum};路径：{file}");
                            }

                            // 报告进度（BackgroundWorker 能安全处理跨线程的进度报告）
                            int progressPercentage = (int)((currentCount / (float)_selectedFiles.Count) * 100);
                            backgroundWorker1.ReportProgress(progressPercentage, result); // 可传递结果用于实时显示
                        });

                        // 所有并行任务完成后，统计最终结果
                        successCount = resultsBag.Count(r => r.res);
                        failCount = resultsBag.Count(r => !r.res);
                        totalImported = resultsBag.Sum(r => r.ImpNum);

                        e.Result = new
                        {
                            Success = failCount == 0,
                            Message = $"统计结果: (耗时 {(DateTime.Now - dt).ToString()}),成功 {successCount} 个，失败 {failCount} 个，总计导入 {totalImported} 条记录"
                        };

                    }
                    catch (Exception ex)
                    {
                        LogMessage($"任务执行过程中发生异常: {ex.Message}");
                    }
                    break;

                default:
                    LogMessage("未知的处理类型，操作中止。");
                    e.Result = new
                    {
                        Success = false,
                        Message = "未知的处理类型，操作中止。"
                    };
                    return;
            }


        }

        /// <summary>
        /// 后台任务进度更新事件处理程序
        /// </summary>
        /// <param name="sender">事件发送者</param>
        /// <param name="e">事件参数，包含进度百分比</param>
        private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
        {
            toolStripStatusLabel1.Text = $"处理中... {e.ProgressPercentage}%";
        }

        /// <summary>
        /// 后台任务完成事件处理程序
        /// </summary>
        /// <param name="sender">事件发送者</param>
        /// <param name="e">事件参数，包含任务执行结果</param>
        private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            try
            {
                // 恢复按钮可用性
                btnImportFiles.Enabled = true;
                btnExportData.Enabled = true;
                btnExportMissingInfo.Enabled = true;
                toolStripStatusLabel1.Text = "准备就绪 - 数据处理程序";

                // 处理任务结果
                if (e.Result != null)
                {
                    dynamic result = e.Result;
                    LogMessage(result.Message.ToString());

                    if ((bool)result.Success)
                    {
                        MessageBox.Show(result.Message.ToString(), "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                    else
                    {
                        MessageBox.Show(result.Message.ToString(), "失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }

                // 重新加载月份列表，以显示新导入的数据
                updateCmbMonth();
            }
            catch (Exception ex)
            {
                LogMessage($"操作完成处理时出错：{ex.Message}");
            }
        }

        #endregion
        /// <summary>
        /// 导入文件按钮点击事件处理程序
        /// 打开文件选择对话框，允许用户选择多个Excel文件进行导入
        /// </summary>
        /// <param name="sender">事件发送者</param>
        /// <param name="e">事件参数</param>
        private void btnImportFiles_Click(object sender, EventArgs e)
        {
            using (var openFileDialog = new OpenFileDialog())
            {
                openFileDialog.Multiselect = true;
                openFileDialog.Filter = "Excel文件 (*.xlsx;*.xls)|*.xlsx;*.xls|所有文件 (*.*)|*.*";
                openFileDialog.Title = "选择要导入的文件";

                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    // 选择了文件，开始处理
                    _selectedFiles = openFileDialog.FileNames.ToList();

                    if (!backgroundWorker1.IsBusy)
                    {
                        dt = DateTime.Now;
                        LogMessage($"开始导入{_selectedFiles.Count}个文件...");
                        // 禁用相关按钮防止重复操作
                        btnImportFiles.Enabled = false;
                        btnExportData.Enabled = false;
                        btnExportMissingInfo.Enabled = false;
                        // 启动后台导入任务
                        backgroundWorker1.RunWorkerAsync();
                    }
                }
            }
        }

        /// <summary>
        /// 导出缺失信息按钮点击事件处理程序
        /// 执行数据库匹配操作并导出未匹配的数据信息
        /// </summary>
        /// <param name="sender">事件发送者</param>
        /// <param name="e">事件参数</param>
        private async void btnExportMissingInfo_Click(object sender, EventArgs e)
        {
            btnExportMissingInfo.Enabled = false; // 防止重复点击
            string updateMon = cmbMonth.Text;
            bool isMatchInit = chbisMatchInit.Checked;
            try
            {
                // 创建进度报告对象，用于在UI线程显示进度消息
                var progress = new Progress<string>(message =>
                {
                    // 这个回调会在UI线程上自动执行
                    LogMessage(message);
                });

                // 执行数据库匹配操作
                dbMatchServer _dbs = new(updateMon, progress);
                if (_dbs._isInit)
                {
                    await Task.Run(() => _dbs.dbMatch(2, isMatchInit));
                    _dbs.Dispose();// 释放资源
                    LogMessage("数据库匹配操作已完成。");
                }
                else
                {
                    LogMessage($"数据库匹配操作异常:{_dbs._initError}");
                }

                // 导出未匹配的数据信息
                dbExportServer _dbExport = new(updateMon, progress);
                if (_dbExport._isInit)
                {
                    bool isMissing = false;
                    string expDictory = string.Empty;
                    await Task.Run(() => isMissing = _dbExport.TryExportUnMatchedData(out expDictory));
                    _dbExport.Dispose();//释放资源
                    if (isMissing)
                    {
                        LogMessage($"已输出缺失信息,目录：{expDictory}");
                    }
                    else
                    {
                        LogMessage($"没有缺失信息,可直接导出结果！");
                    }
                }
                else
                {
                    LogMessage($"数据库导出操作异常:{_dbExport._initError}");
                }

                MessageBox.Show("数据库匹配操作已完成。", "完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                LogMessage($"操作发生错误: {ex.Message}");
            }
            finally
            {
                btnExportMissingInfo.Enabled = true;
            }
        }

        /// <summary>
        /// 导出数据按钮点击事件处理程序
        /// 导出指定月份的统计结果数据
        /// </summary>
        /// <param name="sender">事件发送者</param>
        /// <param name="e">事件参数</param>
        private async void btnExportData_Click(object sender, EventArgs e)
        {
            string updateMon = cmbMonth.Text;
            try
            {
                // 创建进度报告对象，用于在UI线程显示进度消息
                var progress = new Progress<string>(message =>
                {
                    // 这个回调会在UI线程上自动执行
                    LogMessage(message);
                });

                LogMessage($"开始导出{updateMon}统计数据");
                // 创建数据导出服务实例
                dbExportServer _dbExport = new(updateMon, progress);
                if (_dbExport._isInit)
                {
                    bool isMissing = false;
                    string expDictory = string.Empty;
                    // 异步执行数据导出操作
                    await Task.Run(() => isMissing = _dbExport.TryExportResultData(out expDictory));
                    _dbExport.Dispose();//释放资源
                    if (isMissing)
                    {
                        LogMessage($"已输出汇总信息,目录：{expDictory}");
                    }
                    else
                    {
                        LogMessage($"没有数据可输出");
                    }
                }
                else
                {
                    LogMessage($"数据库导出操作异常:{_dbExport._initError}");
                }
            }
            catch (Exception ex)
            {
                LogMessage($"操作发生错误: {ex.Message}");
            }
            finally
            {
                btnExportData.Enabled = true;
            }
        }
    }
}
